Jersey-2.x-User-Guide

3.1. Root Resource Classes 根资源类

Root Resource Classes是带有 @PATH 注解的,包含至少一个 @PATH 注解的方法或者方法带有 @GET, @PUT, @POST, @DELETE 资源方法指示器注解的资源方法的 POJOs (Plain Old Java Objects简单洁净Java对象)。资源方法是资源类注解了。这一节就是展示如何使用Java对象内的注解创建一个 Jersey 的RESTful 服务。

下面这段代码就是一个带有JAX-RS注解的简单事例,可以从这里下载.

Example 3.1. 简单hello world根资源类例子

package org.glassfish.jersey.examples.helloworld;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

@Path("helloworld")
public class HelloWorldResource {
    public static final String CLICHED_MESSAGE = "Hello World!";

@GET
@Produces("text/plain")
    public String getHello() {
        return CLICHED_MESSAGE;
    }
}

下面看下 JAX-RS 里面的几个注解

3.1.1. @Path

@PATH 是一个URI的相对路径,在上面的例子中,设置的是本地的 URI 的 /helloworld。这事一个非常简单的关于 @PATH的例子,更有用的是你可以嵌入变量到 URIs 里面

URI 的路径模版是由 URIs 和嵌入 URI 语法的变量组成。变量在运行时将会被匹配到的 URI 的那部分多代替。例如下面的 @Path 注解

@Path("/users/{username}")

按照这种类型的例子,一个用户会方便的填写他的名字,那么 Jersey 服务器也会按照这个 UIR 路径模板响应到这个请求。例如:用户输入了名字“Galileo”,那么服务器就会响应 http://example.com/users/Galileo

为了接收到用户名变量,@PathParam 用在接收请求的方法的参数上,例如:

Example 3.2. 指定的URI路径参数

@Path("/users/{username}")
public class UserResource {

    @GET
    @Produces("text/xml")
    public String getUser(@PathParam("username") String userName) {
        ...
    }
}

它规定匹配正则表达式式要精确到大小写的,如果填写的话会覆盖默认的表达式 [^/]+? ,例如

@Path("users/{username: [a-zA-Z][a-zA-Z_0-9]*}")

这个正则表达式匹配由大小写字符、横杠和数字组成的字符串,如果正则校验不通过,则返回404(没有找到资源)。

一个 @Path的内容是否以"/"开头都没有区别,同样是否以"/"结尾也没有什么区别

3.1.2. @GET, @PUT, @POST, @DELETE, ... (HTTP 方法)

@GET, @PUT, @POST, @DELETE, @HEAD 是JAX-RS 定义的注解,它非常类似与 HTTP 的方法名。在上面的例子中,这些注解是通过HTTP的 GET 方法实现的。资源的响应就是HTTP的响应。

下面这个例子是存储服务的一个片段,是使用 PUT 方法处理创建或者修改存储容器:

Example 3.3. PUT 方法

@PUT
public Response putContainer() {
    System.out.println("PUT CONTAINER " + container);

    URI uri = uriInfo.getAbsolutePath();
    Container c = new Container(container, uri.toString());

    Response r;
    if (!MemoryStore.MS.hasContainer(c)) {
        r = Response.created(uri).build();
    } else {
        r = Response.noContent().build();
    }

    MemoryStore.MS.createContainer(c);
    return r;
}

如果没有明确的定义的话,JAX-RS 运行的时候默认支持 HEAD 和 OPTIONS 方法。HEAD 运行时将调用 get 方法的实现(如果存在)和忽略响应实体(如果设置)。一个响应返回 OPTIONS 的方法取决于所要求的媒体类型在头文件中 'Accept' 的定义。 OPTIONS 方法可以返回一组支持资源的方法在 头文件中 'Allow' 或返回 WADL 文件的进行设置。更多信息见https://jersey.java.net/documentation/latest/wadl.html节。

3.1.3. @Produces

@Produces是定义返回值给客户端的 MIME 媒体类型。在下面这个例子里面,将会返回一个text/plainMIME 媒体类型的相应。@Produces既可以应用在类的水平上,也可以作用与方法的水平。这里是一个例子:

Example 3.4. 指定输出文件的MIME类型

@Path("/myResource")
@Produces("text/plain")
public class SomeResource {
    @GET
    public String doGetAsPlainText() {
        ...
    }

    @GET
    @Produces("text/html")
    public String doGetAsHtml() {
        ...
    }
}

这个 doGetAsPlainText 方法默认使用类水平的 @Produces 注解内容,也就是text/plain 。而 doGetAsHtml 方法使用方法水平上的@Produces,也就是text/html。也就是说方法水平层面的@Produces 会覆盖类层面的@Produces

如果一个资源类是能够生产多个 MIME 媒体类型,资源的方法的响应将会对应对于客户端来说最可接受的媒体类型。HTTP 请求头部宣布接受什么是最容易被接受的。例如,如果接受头部是 Accept: text/plain 然后dogetasplaintext 方法会被调用。如果接受标题是Accept: text/plain;q=0.9, text/htm,即客户可以接受 text/plaintext/html ,但更容易接收后者的媒体类型,然后 dogetashtml 方法会被调用。

@Produces 可以定义多个返回类型,例如:

Example 3.5. 使用多个返回类型

@GET
@Produces({"application/xml", "application/json"})
public String doGetAsXmlOrJson() {
    ...
}

无论 application/xml 或者 application/json 那个匹配上了,都会执行 doGetAsXmlOrJson,如果两个都匹配了,那么会选择首先匹配的那个

服务器也可选的指定个别媒体类型的品质因数。这些是客户端的决定的如何才是可接受的。例如:

Example 3.6. 服务器端内容协商

@GET
@Produces({"application/xml; qs=0.9", "application/json"})
public String doGetAsXmlOrJson() {
    ...
}

在上面的示例,如果客户端是接受 application/xml 或者 application/json (一样),那么服务器总是发送 application/json,因为 application/xml 有一个较低的品质因数。

上面的例子是指明确清楚的 MIME 媒体类型。最好让它用常量来表示,这样可能会降低印刷错误。具体见 MediaType的常量字段值。

3.1.4. @Consumes

@Consumes注释是用来指定表示可由资源消耗的 MIME 媒体类型。上面的例子可以修改设置如下:

Example 3.7. 指定输入 MIME 类型:

@POST
@Consumes("text/plain")
public void postClichedMessage(String message) {
    // Store the message
}

在这个例子中,该 Java 方法将消耗表示确定的 MIME 媒体类型text/plain 。注意资源的方法返回 void 。这意味着没有内容返回,而是一个204 状态码响应(204是指“无内容”)将返回到客户端。

@Consumes既可以应用在类的水平上,也可以作用与方法的水平,而且可以声明不只一种类型。